﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LinqToTwitter;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Timers;
using System.Net;

namespace TwitCast
{
	public sealed class Timeline
    {
        #region Members
        private string screenName;
		private int maximumTweetsPerRefresh = 10;
		private DateTime lastTweetDate;

		private ITwitterAuthorization authorization;
		private TwitterContext context;
		private List<Status> tweets;

		private Timer refreshTimer;

		private bool isBusy;
		private bool cancelRefresh;

		private StatusType statusType = StatusType.Friends;
        #endregion

        #region Properties
        /// <summary>
		/// Gets the current tweets in this timeline
		/// </summary>
		public List<Status> Tweets
		{
			get
			{
				return this.tweets;
			}
		}

		public StatusType StatusType
		{
			get { return this.statusType; }
			set { this.statusType = value; }
		}
		#endregion

		#region Construction and Initialization
		public Timeline()
		{
			if (String.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterScreenname"]))
				throw new ArgumentException("twitterScreenname cannot be empty");

			this.screenName = ConfigurationManager.AppSettings["twitterScreenname"];

			this.tweets = new List<Status>();

			this.InitializeContext();
			this.InitializeTimer();
		}

		private void InitializeContext()
		{
            this.authorization = new DesktopOAuthAuthorization();

			this.context = new TwitterContext((ITwitterAuthorization)authorization, "https://api.twitter.com/1/", "http://search.twitter.com/");
            
            var oauth = (DesktopOAuthAuthorization)context.AuthorizedClient;
            oauth.GetVerifier = () =>
                {
                    return OAuthPin.ShowOAuthPin(null);
                };

            authorization.SignOn();
		}

		private void InitializeTimer()
		{
			double interval = 1 * 60 * 1000;

			if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["refreshInterval"]))
			{
				Double.TryParse(ConfigurationManager.AppSettings["refreshInterval"], out interval);
			}

			this.refreshTimer = new Timer(interval);
			this.refreshTimer.Enabled = false; // Start disabled
			this.refreshTimer.Elapsed += new ElapsedEventHandler(refreshTimer_Elapsed);
		}
		#endregion

		#region Events
		private void refreshTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			RefreshTimeline();
		}

		public event EventHandler<EventArgs> NewTweetsAvailable;

		private void OnNewTweetsAvailable()
		{
			if (NewTweetsAvailable != null)
			{
				NewTweetsAvailable(this, EventArgs.Empty);
			}
		}
		#endregion

		#region Refresh Methods
		private void RefreshTimeline()
		{
			if (isBusy)
				return;

			// We're busy
			isBusy = true;

			var statusTweets =
			   from tweet in this.context.Status
			   where tweet.Type == statusType
					 && tweet.ScreenName == this.screenName
					 && tweet.Count == maximumTweetsPerRefresh
					 && tweet.CreatedAt > lastTweetDate
			   select tweet;

			// Should we cancel?
			if (cancelRefresh)
			{
				cancelRefresh = false;
				isBusy = false;
				return;
			}

			try
			{
				// Load the tweets
				List<Status> newTweets = statusTweets.ToList();

				// Should we cancel?
				if (cancelRefresh)
				{
					cancelRefresh = false;
					isBusy = false;
					return;
				}

				if (newTweets.Count > 0)
				{
					// Add the new tweets
					this.tweets.AddRange(newTweets);

					// Sort the tweets
					this.tweets.Sort(delegate(Status x, Status y) { return (x.CreatedAt.CompareTo(y.CreatedAt)); });

					// Copy the CreatedAt date of the last tweet
					// Note: do this after sort or else beware!
					lastTweetDate = this.tweets[this.tweets.Count - 1].CreatedAt;

					// Signal any listeners
					OnNewTweetsAvailable();
				}
			}
			catch (Exception)
			{
			}
			finally
			{
				isBusy = false;
			}
		}
		#endregion

		#region Control Methods
		public void Start()
		{
			if(!this.refreshTimer.Enabled)
				this.refreshTimer.Start();

			// Start the Refresh method if this is the first run
			if (this.lastTweetDate == DateTime.MinValue)
				this.RefreshTimeline();
		}

		public void Stop()
		{
			if (this.refreshTimer.Enabled)
			{
				if (isBusy)
					cancelRefresh = true;

				this.refreshTimer.Stop();
			}
		}
		#endregion
	}
}
